package my.mybatis.plugin;

import org.mybatis.generator.api.*;
import org.mybatis.generator.api.dom.java.CompilationUnit;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.JavaVisibility;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.Document;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.config.Context;
import org.mybatis.generator.config.JavaClientGeneratorConfiguration;
import org.mybatis.generator.config.SqlMapGeneratorConfiguration;
import org.mybatis.generator.exception.ShellException;
import org.mybatis.generator.internal.DefaultShellCallback;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import static org.mybatis.generator.internal.util.StringUtility.stringHasValue;

public class ExtendMapperPlugin extends PluginAdapter {

    private static final String DEFAULT_DAO_SUPER_CLASS = "my.mybatis.base.BaseMapper";
    private static final String DEFAULT_EXPAND_DAO_SUPER_CLASS = "";
    private static final String EXTEND_PACKAGE_NAME = ".extend";
    private String daoTargetDir;
    private String daoTargetPackage;
    private List<String> sqlMapFiles = new ArrayList();
    private String daoSuperClass;

    // 扩展
    private String extendDaoTargetPackage;
    private String extendDaoSuperClass;
    private String xmlTargetProject;
    private String xmlTargetPackage;
    private boolean isAddAnnotation = false;

    private ShellCallback shellCallback = null;

    public ExtendMapperPlugin() {
        shellCallback = new DefaultShellCallback(false);
    }

    /**
     * 验证参数是否有效
     *
     * @param warnings
     * @return
     */
    public boolean validate(List<String> warnings) {
        //取基本配置，作为extend的配置，（减少配置项，提高易用性）
        Context context = this.getContext();
        JavaClientGeneratorConfiguration javaClientGeneratorConfiguration = context.getJavaClientGeneratorConfiguration();
        daoTargetDir = javaClientGeneratorConfiguration.getTargetProject();
        daoTargetPackage = javaClientGeneratorConfiguration.getTargetPackage();


        daoSuperClass = properties.getProperty("daoSuperClass");
        if (!stringHasValue(daoSuperClass)) {
            daoSuperClass = DEFAULT_DAO_SUPER_CLASS;
        }

        extendDaoTargetPackage = daoTargetPackage + EXTEND_PACKAGE_NAME;

        SqlMapGeneratorConfiguration sqlMapGeneratorConfiguration = context.getSqlMapGeneratorConfiguration();
        xmlTargetProject = sqlMapGeneratorConfiguration.getTargetProject();
        xmlTargetPackage = sqlMapGeneratorConfiguration.getTargetPackage() + EXTEND_PACKAGE_NAME;

        extendDaoSuperClass = properties.getProperty("extendDaoSuperClass");
        if (!stringHasValue(extendDaoSuperClass)) {
            extendDaoSuperClass = DEFAULT_EXPAND_DAO_SUPER_CLASS;
        }
        if(stringHasValue(properties.getProperty("isAddAnnotation"))) {
            isAddAnnotation = Boolean.valueOf(properties.getProperty("isAddAnnotation"));
        }
        return true;
    }

    @Override
    public boolean sqlMapDocumentGenerated(Document document, IntrospectedTable introspectedTable) {
//        XmlElement select = new XmlElement("select");
//        select.addAttribute(new Attribute("id", "selectAll"));
//        select.addAttribute(new Attribute("resultMap", "BaseResultMap"));
//        select.addAttribute(new Attribute("parameterType", introspectedTable.getBaseRecordType()));
//        select.addElement(new TextElement(" select * from "+ introspectedTable.getFullyQualifiedTableNameAtRuntime()));
//
//        XmlElement parentElement = document.getRootElement();
//        parentElement.addElement(select);
        return super.sqlMapDocumentGenerated(document, introspectedTable);
    }

    public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {
        JavaFormatter javaFormatter = context.getJavaFormatter();
        List<GeneratedJavaFile> mapperJavaFiles = new ArrayList<GeneratedJavaFile>();
        for (GeneratedJavaFile javaFile : introspectedTable.getGeneratedJavaFiles()) {
            CompilationUnit unit = javaFile.getCompilationUnit();
            FullyQualifiedJavaType baseModelJavaType = unit.getType();

            String shortName = baseModelJavaType.getShortName();

            GeneratedJavaFile mapperJavafile = null;

            if (shortName.endsWith("Mapper")) { // 扩展Mapper
                if (stringHasValue(extendDaoTargetPackage)) {
                    Interface mapperInterface = new Interface(
                            extendDaoTargetPackage + "." + shortName.replace("Mapper", "ExtendMapper"));
                    mapperInterface.setVisibility(JavaVisibility.PUBLIC);
                    mapperInterface.addJavaDocLine("/**");
                    mapperInterface.addJavaDocLine(" * " + shortName + "扩展");
                    mapperInterface.addJavaDocLine(" */");

                    if(isAddAnnotation){
                        mapperInterface.addAnnotation("@Repository");//添加这个注解，省得idea包扫描报错
                        mapperInterface.addImportedType(new FullyQualifiedJavaType("org.springframework.stereotype.Repository"));
                    }

                    FullyQualifiedJavaType daoSuperType = new FullyQualifiedJavaType(baseModelJavaType.getFullyQualifiedName());
                    mapperInterface.addImportedType(daoSuperType);
                    mapperInterface.addSuperInterface(daoSuperType);

                    mapperJavafile = new GeneratedJavaFile(mapperInterface, daoTargetDir, javaFormatter);
                    try {
                        File mapperDir = shellCallback.getDirectory(daoTargetDir, extendDaoTargetPackage);
                        File mapperFile = new File(mapperDir, mapperJavafile.getFileName());
                        // 文件不存在
                        if (!mapperFile.exists()) {
                            mapperJavaFiles.add(mapperJavafile);
                        }
                    } catch (ShellException e) {
                        e.printStackTrace();
                    }
                }
            } else if (!shortName.endsWith("Example")) { // CRUD Mapper
//                Interface mapperInterface = new Interface(daoTargetPackage + "." + shortName + "Mapper");
//
//                mapperInterface.setVisibility(JavaVisibility.PUBLIC);
//                mapperInterface.addJavaDocLine("/**");
//                mapperInterface.addJavaDocLine(" * 由MyBatis Generator工具自动生成，请不要手动修改");
//                mapperInterface.addJavaDocLine(" */");
//
//                FullyQualifiedJavaType daoSuperType = new FullyQualifiedJavaType(daoSuperClass);
//                // 添加泛型支持
//                daoSuperType.addTypeArgument(baseModelJavaType);
//                mapperInterface.addImportedType(baseModelJavaType);
//                mapperInterface.addImportedType(daoSuperType);
//                mapperInterface.addSuperInterface(daoSuperType);
//
//                mapperJavafile = new GeneratedJavaFile(mapperInterface, daoTargetDir, javaFormatter);
//                mapperJavaFiles.add(mapperJavafile);

            }
        }
        return mapperJavaFiles;
    }

    @Override
    public List<GeneratedXmlFile> contextGenerateAdditionalXmlFiles(IntrospectedTable introspectedTable) {
        List<GeneratedXmlFile> answer = new ArrayList(1);
        for (GeneratedJavaFile javaFile : introspectedTable.getGeneratedJavaFiles()) {
            CompilationUnit unit = javaFile.getCompilationUnit();
            FullyQualifiedJavaType baseModelJavaType = unit.getType();

            String shortName = baseModelJavaType.getShortName();
            if (shortName.endsWith("Mapper")) {
                shortName = shortName.replace("Mapper", "ExtendMapper");
                //让extendMapper.xml 不要被覆盖
                try {
                    File mapperDir = shellCallback.getDirectory(xmlTargetProject,xmlTargetPackage);
                    File mapperFile = new File(mapperDir, shortName + ".xml");
                    if (mapperFile.exists()) {
                       continue;
                    }
                } catch (ShellException e) {
                    e.printStackTrace();
                }

                Document document = new Document("-//mybatis.org//DTD Mapper 3.0//EN", "http://mybatis.org/dtd/mybatis-3-mapper.dtd");
                XmlElement root = new XmlElement("mapper");
                root.addAttribute(new Attribute("namespace", extendDaoTargetPackage + "." + shortName));
                document.setRootElement(root);
                root.addElement(new TextElement(System.getProperty("line.separator")));
                GeneratedXmlFile gxf = new GeneratedXmlFile(document, shortName + ".xml", xmlTargetPackage, xmlTargetProject, false, this.context.getXmlFormatter());
                answer.add(gxf);
            }
        }

        return answer;
    }


    public boolean sqlMapGenerated(GeneratedXmlFile sqlMap, IntrospectedTable introspectedTable) {
        StringBuilder sb = new StringBuilder();
        sb.append(sqlMap.getTargetPackage());
        sb.append('.');
        String temp = sb.toString();
        sb.setLength(0);
        sb.append(temp.replace('.', '/'));
        sb.append(sqlMap.getFileName());
        this.sqlMapFiles.add(sb.toString());
        return true;
    }


}